#include "ObjectManager.h"


#include "OgreFrameWork.h"

#include "GameManager.h"

#include "component/ComponentPosition.h"
#include "component/ComponentRenderable.h"
#include "component/ComponentMovable.h"

#include "Util.h"

ObjectManager::ObjectManager()
{
    //ctor
    m_player=0;
    m_isInitialized=false;
}

ObjectManager::~ObjectManager()
{
    //dtor
}


/** @brief clear
  *
  * @todo: document this function
  */
void ObjectManager::clear()
{
    /*
    if (m_isInitialized)
    {
        std::list<Object*>::iterator it;
        for ( it=m_tabObjects.begin() ; it != m_tabObjects.end(); it++ )
        {
            (*it)->clear();
            delete (*it);
        }
        m_tabObjects.clear();


        m_isInitialized=false;
    }
    */
}

/** @brief update
  *
  * @todo: document this function
  */
void ObjectManager::update(double timeSinceLastFrame)
{

    std::map<std::string, Object*>::iterator it;

    for ( it=m_tabObjects.begin() ; it != m_tabObjects.end(); it++ )
    {
        it->second->update(timeSinceLastFrame);

    }





}

/** @brief init
  *
  * @todo: document this function
  */
void ObjectManager::init()
{
    if (!m_isInitialized)
    {








        m_isInitialized=true;
    }
    else
        OgreFramework::getSingletonPtr()->m_pLog->logMessage("!!!!!   ObjectManager already initialized");







}



/** @brief createObject
  *
  * @todo: document this function
  */



Object* ObjectManager::createObject(std::string _name, std::string _type, Ogre::Vector2 _position)
{
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Creating object  " + _name +"  of type  "+_type);
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("loading from xml file : ../data/objects/"+_type+".xml");

    Object* obj = new Object();
    obj->setName(_name);
    createObjectFromXMLFile(obj, "../data/objects/"+_type+".xml");

    if (obj!=0)
    {

        m_tabObjects.insert(std::pair<std::string, Object*>(_name,obj));


        obj->init();
        obj->update(1);
        obj->setPosition(addYtoVector2(_position));
    }

    return obj;
}

Object* ObjectManager::loadFromXML(Object* _obj, TiXmlElement* parentElement)
{


    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Loading Object From XML");
    TiXmlNode *ComponentsXML = parentElement->FirstChild( "Components" );
    TiXmlNode   * compXML = ComponentsXML->FirstChild();

    ComponentArguments compArgs;
    Object* obj = _obj;

//iterate on each components
    for( compXML = ComponentsXML->FirstChild(); compXML; compXML = compXML->NextSibling() )
    {
        OgreFramework::getSingletonPtr()->m_pLog->logMessage("Component  :"+std::string(compXML->Value()));
        //iterate on each arguments
        TiXmlNode   * argsXML = compXML->FirstChild();
        for( argsXML = compXML->FirstChild(); argsXML; argsXML = argsXML->NextSibling() )
        {
            //OgreFramework::getSingletonPtr()->m_pLog->logMessage("        compXML  :"+std::string(argsXML->Value()));
            if (std::string(argsXML->ToElement()->Attribute("type")).compare("float")==0)
            {
                double a;
                argsXML->ToElement()->Attribute(std::string("value").c_str(),&a);
                OgreFramework::getSingletonPtr()->m_pLog->logMessage("        params  :"+std::string(argsXML->Value())+"   "+Ogre::StringConverter::toString(float(a)));
                compArgs.addArgument(std::string(argsXML->Value()),float(a) );
            }

            else if (std::string(argsXML->ToElement()->Attribute("type")).compare("int")==0)
            {
                int a;
                argsXML->ToElement()->Attribute(std::string("value").c_str(),&a);
                OgreFramework::getSingletonPtr()->m_pLog->logMessage("        params  :"+std::string(argsXML->Value())+"   "+Ogre::StringConverter::toString(int(a)));
                compArgs.addArgument(std::string(argsXML->Value()),int(a) );
            }


            else if (std::string(argsXML->ToElement()->Attribute("type")).compare("string")==0)
            {
                std::string a = std::string(argsXML->ToElement()->Attribute(std::string("value").c_str()));
                OgreFramework::getSingletonPtr()->m_pLog->logMessage("        params  :"+std::string(argsXML->Value())+"   "+a);
                compArgs.addArgument(std::string(argsXML->Value()),a );
            }

            else if (std::string(argsXML->ToElement()->Attribute("type")).compare("vector3")==0)
            {

                double x,y,z;
                argsXML->ToElement()->Attribute(std::string("x").c_str(),&x);
                argsXML->ToElement()->Attribute(std::string("y").c_str(),&y);
                argsXML->ToElement()->Attribute(std::string("z").c_str(),&z);
                Ogre::Vector3  a = Ogre::Vector3(x,y,z);
                OgreFramework::getSingletonPtr()->m_pLog->logMessage("        params  :"+std::string(argsXML->Value())+"   "+Ogre::StringConverter::toString(a));
                compArgs.addArgument(std::string(argsXML->Value()),a );
            }


        }



        obj->createComponent(std::string(compXML->Value()), compArgs);

    }




    return obj;

}

Object* ObjectManager::createObjectFromXMLFile(Object* _obj, std::string _path)
{
    TiXmlDocument doc(_path.c_str());
    bool loadOkay = doc.LoadFile();
    if (loadOkay)
    {
        TiXmlElement *pRoot;
        pRoot = doc.FirstChildElement( "object" );
        if ( pRoot )
        {

            return loadFromXML(_obj, pRoot);
        }


    }
}




/** @brief giveOrderToGoTo
  *
  * @todo: document this function
  */
void ObjectManager::giveOrderToGoTo(Ogre::Vector2 _position)
{

if (m_player!=0)
{


    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Give order to player...");

    Ogre::Vector2 pos = removeYtoVector3(((ComponentPosition*)getPlayer()->getComponent("Position"))->getPosition());
    std::list<Ogre::Vector2> listePoints = GameManager::getInstance()->getLevelMgrPtr()->searchPath(pos , _position);

    Ogre::stringstream str;
    str << "Nb Waypoints  " << listePoints.size();
    OgreFramework::getSingletonPtr()->m_pLog->logMessage(str.str());
    if (listePoints.size()>0)
    {
        listePoints.pop_back();
        listePoints.push_back(_position);
        if(m_player->hasComponent("Movable"))
        {
            ( (ComponentMovable*)m_player->getComponent("Movable"))->addWayPointsAfterClear(listePoints);
        }

    }
}

}

/** @brief giveOrderMovableToGoTo
  *
  * @todo: document this function
  */
void ObjectManager::giveOrderMovableToGoTo(Object* _object, Ogre::Vector2 _position)
{
    /*
    OgreFramework::getSingletonPtr()->m_pLog->logMessage("Give order to creature...");



    Ogre::Vector2 pos = _object->getPosition();
    std::list<Ogre::Vector2> listePoints = GameManager::getInstance()->getLevelMgrPtr()->searchPath(pos , _position);

    Ogre::stringstream str;
    str << "Nb Waypoints  Movable" << listePoints.size();
    OgreFramework::getSingletonPtr()->m_pLog->logMessage(str.str());

    listePoints.push_back(_position);



        ((MovableObject* )_object)->addWayPoints(listePoints);
    */

}

/** @brief getObjectsWithComponentNear
  *
  * @todo: document this function
  */
std::list<Object*> ObjectManager::getObjectsWithComponentNear(Ogre::Vector3 _position, float _distance, std::string _component)
{
    std::list<Object*> objs;

    std::map<std::string, Object*>::iterator it;

    for ( it=m_tabObjects.begin() ; it != m_tabObjects.end(); it++ )
    {
        if(it->second->getPosition().distance(_position)<_distance)
        {
            if (it->second->hasComponent(_component))
                objs.push_back(it->second);
        }

    }
    return objs;
}

/** @brief getObjectsNear
  *
  * @todo: document this function
  */
std::list<Object*> ObjectManager::getObjectsNear(Ogre::Vector3 _position, float _distance)
{
    std::list<Object*> objs;

    std::map<std::string, Object*>::iterator it;

    for ( it=m_tabObjects.begin() ; it != m_tabObjects.end(); it++ )
    {
        if(it->second->getPosition().distance(_position)<_distance)
        {
            objs.push_back(it->second);
        }

    }
    return objs;
}


/** @brief removeObject
  *
  * @todo: document this function
  */
void ObjectManager::removeObject(std::string _name)
{

}

/** @brief removeObject
  *
  * @todo: document this function
  */
void ObjectManager::removeObject(Object* _item)
{

}

/** @brief getObjectFromName
  *
  * @todo: document this function
  */
Object* ObjectManager::getObjectFromName(std::string _name)
{

    if (m_tabObjects.count(_name)>0)
    {
        return m_tabObjects[_name];
    }
    else
    {
        OgreFramework::getSingletonPtr()->m_pLog->logMessage("ERROR : Object "+_name+" doesn't exist");
        return 0;
    }

}





